package controllers

import (
	"encoding/json"
	"errors"
	beego "github.com/beego/beego/v2/server/web"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
	"log"
	"math"
	"mime/multipart"
	"path/filepath"
	"pet-management-project/models"
	"strconv"
	"time"
)

type PetControllers struct {
	beego.Controller
}

type Res struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

func (c *PetControllers) Register() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	username := c.GetString("username")
	password := c.GetString("password")
	userName := c.GetString("userName")

	passwordMD5 := MD5(password)

	user := models.UserInfo{
		Model:    gorm.Model{},
		Username: username,
		Password: passwordMD5,
		UserName: userName,
	}

	err := models.DB.Create(&user).Error

	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "注册失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	} else {
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "注册成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) Login() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	username := c.GetString("username")
	password := c.GetString("password")

	if username == "" || password == "" {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "请确保用户名或密码填写正确",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	var user models.UserInfo
	err := models.DB.Where("username = ?", username).First(&user).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "用户名不存在，请重新输入",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	key := "user:login:" + username

	count, rErr := models.Rdb.Get(models.Ctx, key).Int()
	if errors.Is(rErr, redis.Nil) {
		count = 0
	}

	if count >= 3 {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "密码错误已达三次，禁止登录",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	passwordMD5 := MD5(password)
	if passwordMD5 != user.Password {
		_ = models.Rdb.Set(models.Ctx, key, count+1, time.Hour*2).Err()
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "密码输入错误，请重新输入",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	} else {
		_ = models.Rdb.Set(models.Ctx, key, 0, 0).Err()

		c.Data["json"] = Res{
			Code: 200,
			Msg:  "登陆成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) CateAdd() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	cateName := c.GetString("cate_name")

	petCate := models.PetCate{
		Model:    gorm.Model{},
		CateName: cateName,
	}
	err := models.DB.Create(&petCate).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "宠物分类添加失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	} else {
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物分类添加成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) PetAdd() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	petName := c.GetString("pet_name")
	petSex := c.GetString("pet_sex")
	petAge, _ := c.GetInt("pet_age")
	petTypeId, _ := c.GetInt("pet_type_id")
	img, header, err := c.GetFile("img")
	username := c.GetString("username")

	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "宠物图片获取失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	defer func(img multipart.File) {
		err = img.Close()
		if err != nil {

		}
	}(img)

	ImgType := map[string]bool{
		".png":  true,
		".jpg":  true,
		".jpeg": true,
	}

	if !ImgType[filepath.Ext(header.Filename)] {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "不支持的图片格式，请重新上传",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	size := float64(header.Size) / 1024 / 1024

	if size > 1 {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "图片大小限制1Mb，请重新上传",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	path := "static/img/" + header.Filename

	err = c.SaveToFile("img", path)

	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "图片上传失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	var user models.UserInfo
	err = models.DB.Where("username = ?", username).First(&user).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "不存在此用户，无法关联宠物",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}
	petUserId := user.ID
	petInfo := models.PetInfo{
		Model:     gorm.Model{},
		PetName:   petName,
		PetSex:    petSex,
		PetAge:    petAge,
		PetTypeId: petTypeId,
		PetUserId: int(petUserId),
		Img:       "http://127.0.0.1:8080/" + path,
	}

	err = models.DB.Create(&petInfo).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "宠物信息添加失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	} else {
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物信息添加成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) PetList() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	page, _ := c.GetInt("page", 1)
	size, _ := c.GetInt("size", 5)

	offset := (page - 1) * size

	var count int64
	models.DB.Model(&models.PetInfo{}).Count(&count)

	sum := int(math.Ceil(float64(count) / float64(size)))

	up := page - 1
	if up < 1 {
		up = page
	}

	down := page + 1
	if down > sum {
		down = page
	}

	var petInfo []models.PetInfo

	// 先从redis中获取缓存数据
	key := "pet:list:page_" + strconv.Itoa(page) + "size_" + strconv.Itoa(size)

	result, err := models.Rdb.Get(models.Ctx, key).Result()

	if result == "" || errors.Is(err, redis.Nil) {
		// 没有数据，从mysql中获取
		err = models.DB.Limit(size).Offset(offset).Find(&petInfo).Error
		if err != nil {
			c.Data["json"] = Res{
				Code: 400,
				Msg:  "宠物列表查询失败",
				Data: nil,
			}
			_ = c.ServeJSON()
			return
		} else {
			log.Println("Mysql中读取宠物列表数据")
			// 获取到的数据存入redis

			res, _ := json.Marshal(petInfo)

			_ = models.Rdb.Set(models.Ctx, key, res, 0).Err()

			data := map[string]interface{}{
				"data": petInfo,
				"up":   up,
				"down": down,
				"sum":  sum,
			}

			c.Data["json"] = Res{
				Code: 200,
				Msg:  "宠物列表查询成功",
				Data: data,
			}
			_ = c.ServeJSON()
		}
	} else {
		log.Println("Redis中读取宠物列表数据")

		// redis中有数据
		_ = json.Unmarshal([]byte(result), &petInfo)

		data := map[string]interface{}{
			"data": petInfo,
			"up":   up,
			"down": down,
			"sum":  sum,
		}

		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物列表查询成功",
			Data: data,
		}
		_ = c.ServeJSON()
	}

}

func (c *PetControllers) PetDel() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	username := c.GetString("username")
	id := c.GetString("id")

	var user models.UserInfo
	err := models.DB.Where("username = ?", username).First(&user).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "不存在的用户，无法删除",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	var petInfo models.PetInfo

	err = models.DB.Where("id = ?", id).First(&petInfo).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "不存在的宠物信息，无法删除",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	if int(user.ID) != petInfo.PetUserId {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "当前宠物不是您的，删除失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	err = models.DB.Delete(&models.PetInfo{}, id).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物信息删除失败",
			Data: nil,
		}
		_ = c.ServeJSON()
	} else {
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物信息删除成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) PetInfo() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	id := c.GetString("id")

	var petInfo models.PetInfo
	key := "pet:info:" + id
	res, err := models.Rdb.Get(models.Ctx, key).Result()
	if res == "" || errors.Is(err, redis.Nil) {
		err = models.DB.Where("id = ?", id).First(&petInfo).Error
		if err != nil {
			c.Data["json"] = Res{
				Code: 400,
				Msg:  "宠物详情获取失败",
				Data: nil,
			}
			_ = c.ServeJSON()
			return
		} else {
			log.Println("Mysql获取宠物详情数据")
			jsonRes, _ := json.Marshal(petInfo)
			_ = models.Rdb.Set(models.Ctx, key, jsonRes, 0).Err()

			c.Data["json"] = Res{
				Code: 200,
				Msg:  "宠物详情获取成功",
				Data: petInfo,
			}
			_ = c.ServeJSON()

		}
	} else {
		log.Println("Redis获取宠物详情数据")
		_ = json.Unmarshal([]byte(res), &petInfo)

		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物详情获取成功",
			Data: petInfo,
		}
		_ = c.ServeJSON()
	}
}
